#include <string.h> 
#include <sys/stat.h>
#include <fcntl.h> 
#include <errno.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
// 自定义头文件
#include "tlv_protocol.h"

// 发送一个完整的 TLV 包
int send_tlv(int sock_fd, int type, const char* value, int length) {
    tlv_header_t header;
    header.type = type; 
    header.length = length;

    // 1. 发送头部
    if (send_all(sock_fd, &header, sizeof(header)) < 0) {
        perror("send header failed");
        return -1;
    }
    // 2. 发送值 (如果存在)
    if (length > 0) {
        if (send_all(sock_fd, value, length) < 0) {
            perror("send value failed");
            return -1;
        }
    }
    return 0;
}

// 确保发送所有数据 (处理TCP短写)
int send_all(int sock_fd, const void* buffer, int length) {
    int total_sent = 0;
    while (total_sent < length) {
        ssize_t sent = send(sock_fd, (char*)buffer + total_sent, length - total_sent, 0);
        if (sent < 0) return -1;
        total_sent += (int)sent;
    }
    return total_sent;
}

// 确保接收所有数据 (处理TCP短读)
int recv_all(int sock_fd, void* buffer, int length) {
    int total_received = 0;
    while (total_received < length) {
        ssize_t received = recv(sock_fd, (char*)buffer + total_received, length - total_received, 0);
        if (received <= 0) return (int)received; // 错误或连接关闭
        total_received += (int)received;
    }
    return total_received;
}


// 上传函数
int receive_and_write_file(int sockfd, char *file_to_upload) {
    // 创建文件
    int fd = open(file_to_upload, O_WRONLY | O_CREAT | O_TRUNC);
    if (fd == -1) {
        send_tlv(sockfd, RESP_ERROR, NULL, 0);
        return -1;
    }

    // 成功打开文件则返回RESP_OK
    send_tlv(sockfd, RESP_OK, NULL, 0);

    printf("准备接收文件，将保存为 %s\n", file_to_upload);

    while (1) {
        tlv_header_t header;

        // 1. 读取 TLV 头部
        if (recv_all(sockfd, &header, sizeof(header)) <= 0) {
            fprintf(stderr, "与客户端的连接中断！\n");
            close(fd);
            return -1;
        }

        // 判断是否是错误响应
        if (header.type == RESP_ERROR) {
            fprintf(stderr, "客户端返回错误。\n");
            // 接收并打印错误
            if (header.length > 0) {
                char err_msg[4096] = { 0 };
                int len_to_read = header.length < (int)sizeof(err_msg) - 1 ?
                    header.length : sizeof(err_msg) - 1;
                recv_all(sockfd, err_msg, len_to_read);
                fprintf(stderr, "错误信息: %s\n", err_msg);
            }

            close(fd);
            remove(file_to_upload);
            return -1;
        }

        // 判断是否是文件数据
        if (header.type != RESP_FILE_DATA) {
            // 非预期的包类型
            fprintf(stderr, "协议错误: 收到非文件数据包，类型为 %d\n", header.type);
            close(fd);
            remove(file_to_upload);
            return -1;
        }

        // 如果 length 为0，表示文件接收结束
        if (header.length == 0) {
            printf("文件接收完毕。\n");
            break;
        }

        // 读取 value 并写入文件
        char buffer[4096] = { 0 };
        int bytes_to_read = header.length;
        while (bytes_to_read > 0) {
            int chunk_size = bytes_to_read > (int)sizeof(buffer) ?
                sizeof(buffer) : bytes_to_read;

            if (recv_all(sockfd, buffer, chunk_size) <= 0) {
                fprintf(stderr, "连接中断！\n");
                close(fd);
                return -1;
            }

            write(fd, buffer, chunk_size);
            bytes_to_read -= chunk_size;
        }
    }

    // 上传成功
    send_tlv(sockfd, RESP_OK, NULL, 0);

    close(fd);
    return 0;
}

// 下载函数
int send_file_content(int sockfd, char *file_to_download) {
    // 判断服务端下载文件是否存在
    struct stat st;
    if (stat(file_to_download, &st) != 0) {
        char buffer[] = "文件不存在";
        send_tlv(sockfd, RESP_ERROR, buffer, strlen(buffer));
        perror(buffer);
        return -1;
    }

    printf("准备发送文件，将传输为 %s\n", file_to_download);

    int fd = open(file_to_download, O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        return -1;
    }

    int bytes_read = 0;
    char buffer[4096] = { 0 };
    while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
        send_tlv(sockfd, RESP_FILE_DATA, buffer, bytes_read);
    }

    close(fd);

    // 发送结束标志（length为0的tlv数据包)
    send_tlv(sockfd, RESP_FILE_DATA, NULL, 0);

    printf("发送文件成功。");
   
    return 0;
}

